package com.hyt.it.ogt.ks.job;


import java.time.LocalDateTime;
import java.util.List;

import javax.annotation.Resource;

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.ks.mapper.CandidateBrowserInfoMapper;
import com.hyt.it.ogt.ks.model.entity.CandidateBrowserInfo;
import com.hyt.it.ogt.ks.model.entity.CandidatePaper;
import com.hyt.it.ogt.ks.model.vo.CandidateLoginRequestVO;
import com.hyt.it.ogt.ks.service.ICandidatePaperService;
import com.hyt.it.ogt.ks.util.KeyDefineCommon;

/**
 * @author wuyingge
 * @Description 当考生获取下一套未考完试卷，然后清空AccessTime，要不然倒计时会直接按上次记录时间扣除，可能会直接扣完时间
 *             用与解决循环依赖情况下不能使用@Async的问题
 * @createTime 2021年12月06日 15:48:00
 */
@Component
public class CandidateProcessAccessTimeTask {

    @Resource
    private ICandidatePaperService iCandidatePaperService;
    @Resource
    private RedisTemplate redisTemplate;
    @Resource
    private CandidateBrowserInfoMapper candidateBrowserInfoMapper;

    /**
     * 异步修改
     * @param examId
     * @param candidateId
     */
    @Async("executor")
    public void setAccessTimeToNull(String examId, String candidateId) {
        // 获取下一套未考完试卷，然后清空AccessTime，要不然倒计时会直接按上次记录时间扣除，可能会直接扣完时间
        List<CandidatePaper> list = iCandidatePaperService.lambdaQuery()
                .select(CandidatePaper::getId, CandidatePaper::getAccessTime)
                .gt(CandidatePaper::getMixSort, 0).eq(CandidatePaper::getFinish, false)
                .eq(CandidatePaper::getExamId, examId).eq(CandidatePaper::getCandidateId, candidateId).list();
        list.forEach(item -> {
            if(item.getAccessTime() != null) {
                LambdaUpdateWrapper<CandidatePaper> updateWrapper = Wrappers.lambdaUpdate();
                updateWrapper.eq(CandidatePaper::getId, item.getId());
                updateWrapper.set(CandidatePaper::getAccessTime, null);
                iCandidatePaperService.update(updateWrapper);
            }
        });
    }

    @Async("executor")
    public void loginAsyncDealEvent(CandidateLoginRequestVO requestVO, String candidateId) {
        // 删除缓存信息
        this.deleteCache4MobileNotice(requestVO.getExamId(), candidateId);
        // 保存考生浏览器信息
        this.saveCandidateBrowserInfo(requestVO.getExamId(), candidateId, requestVO.getAdmissionNumber(), requestVO.getBrowserInfo());
        // 获取下一套未考完试卷，然后清空AccessTime，要不然倒计时会直接按上次记录时间扣除，可能会直接扣完时间
        List<CandidatePaper> list = iCandidatePaperService.lambdaQuery()
                .select(CandidatePaper::getId, CandidatePaper::getAccessTime)
                .gt(CandidatePaper::getMixSort, 0).eq(CandidatePaper::getFinish, false)
                .eq(CandidatePaper::getExamId, requestVO.getExamId()).eq(CandidatePaper::getCandidateId, candidateId).list();
        list.forEach(item -> {
            if(item.getAccessTime() != null) {
                LambdaUpdateWrapper<CandidatePaper> updateWrapper = Wrappers.lambdaUpdate();
                updateWrapper.eq(CandidatePaper::getId, item.getId());
                updateWrapper.set(CandidatePaper::getAccessTime, null);
                iCandidatePaperService.update(updateWrapper);
            }
        });
    }

    private void deleteCache4MobileNotice(String examId, String candidateId) {
        redisTemplate.delete(KeyDefineCommon.getMobileDeviceOffLineKey(examId, candidateId));
        redisTemplate.delete(KeyDefineCommon.getMobileDeviceMuteKey(examId, candidateId));
        redisTemplate.delete(KeyDefineCommon.getMobileDeviceMuteNoticeKey(examId, candidateId));
        redisTemplate.delete(KeyDefineCommon.getMobileDeviceOffLineNoticeKey(examId, candidateId));
    }

    private void saveCandidateBrowserInfo(String examId, String candidateId, String admissionNumber, String browserInfo) {
        CandidateBrowserInfo candidateBrowserInfo = CandidateBrowserInfo.builder().examId(examId)
                .candidateId(candidateId).admissionNumber(admissionNumber).browserInfo(browserInfo).build();
        candidateBrowserInfo.setId(UUIDUtils.randomUUID());
        candidateBrowserInfo.setCreateDate(LocalDateTime.now());
        candidateBrowserInfoMapper.insert(candidateBrowserInfo);
    }
}
